

#include "widget.h"

#include<QMessageBox>
#include "./ui_widget.h"

#ifdef Q_OS_WIN
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <iphlpapi.h>
#include <wlanapi.h>

#elif defined(Q_OS_LINUX)
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <sys/types.h>
#include <pwd.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <signal.h>
#endif



Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // this->serverProcess=nullptr;
    qDebug()<<"serverProcess";
    this->updateTimer=new QTimer(this);
    qDebug()<<"updateTimer";
    this->isMonitoring=false;
    this->lastNetworkState="无连接";
    this->networkProblemDetected=false;



    QString logDir = QCoreApplication::applicationDirPath() + "/logs";
    this->logwriter=new LogWriter(logDir,this);

    this->logwriter->start();

    connect(updateTimer,&QTimer::timeout,this,&Widget::updateProcessInfo);
    connect(logwriter, &LogWriter::logReadyForUI, this, [=](const QString& formattedLog) {

        ui->plainTextEdit->appendPlainText(formattedLog);

        QScrollBar* scrollBar = ui->plainTextEdit->verticalScrollBar();
        if (scrollBar->value() == scrollBar->maximum()) {  // 判断是否在底部
            scrollBar->setValue(scrollBar->maximum());     // 滚到最新行
        }
    }, Qt::QueuedConnection);
    initTable();

    this->isSelect=false;

    ui->startButton->setEnabled(false);

    ui->plainTextEdit->setReadOnly(true);

    this->isRestarting=false;
}
Widget::~Widget()
{

    if (updateTimer) {
        updateTimer->stop();
    }


    delete ui;
}

void Widget::initTable()
{
    ui->processTable->setColumnCount(6);
    QStringList processCols = {"进程名", "PID", "网络状态", "本地IP:端口",
                               "CPU占用", "内存占用"};
    ui->processTable->setHorizontalHeaderLabels(processCols);
    ui->processTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->processTable->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->processTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);


    //把文件日志写入到view里面去
    ui->plainTextEdit->clear();


    QString logDir = QCoreApplication::applicationDirPath() + "/logs";
    QString todayLogFile = logDir + "/" + QDate::currentDate().toString("yyyy-MM-dd") + ".log";


    QFile file(todayLogFile);
    if (!file.exists()) {
        ui->plainTextEdit->appendPlainText("暂无历史日志");
        return;
    }

    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream in(&file);
        // 逐行读取并显示（避免一次性读取大文件导致卡顿）
        while (!in.atEnd()) {
            QString line = in.readLine();
            ui->plainTextEdit->appendPlainText(line);
        }
        file.close();


        QTextCursor cursor = ui->plainTextEdit->textCursor();
        cursor.movePosition(QTextCursor::End);
        ui->plainTextEdit->setTextCursor(cursor);
    } else {
        ui->plainTextEdit->appendPlainText("无法打开日志文件：" + file.errorString());
    }


}

void Widget::loadProcesses()
{


    if (isMonitoring)
    {
        QMessageBox::information(this, "提示", "已经开始监测");
        return;
    }



    ui->processTable->clearContents();

    const QString serverExeName = "Server.exe"; // 服务器进程名
    const DWORD targetPort = 9999;
    DWORD existingPid = 0;



    QList<DWORD> candidatePids = findPidByProcessName(serverExeName);
    if (!candidatePids.isEmpty()) {
        // 2. 对每个候选 PID，检查是否占用目标端口
        for (DWORD pid : candidatePids) {
            if (isPidUsingTargetPort(pid, targetPort)) {
                existingPid = pid;
                break; // 找到唯一匹配的 PID，退出循环
            }
        }
    }

    if (existingPid != 0) {
        qDebug() << "服务器已运行（PID=" << existingPid << "），直接开始监测";
        serverPid = existingPid;
        startMonitoring(existingPid);
        QMessageBox::information(this, "提示", "服务器已运行，直接开始监测（PID=" + QString::number(existingPid) + "）");


        LogMessage msg;
        msg.content="服务器已启动";
        msg.level=LogMessage::Debug;
        msg.timestamp= QDateTime::currentDateTime();

        this->logwriter->writeQueue(msg);
        return; // 跳过创建新进程的逻辑
    }


#ifdef Q_OS_WIN
    std::wstring widePath = serverPath.toStdWString();
    LPCWSTR lpApplicationName = widePath.c_str(); // 直接传路径到第一个参数
    LPWSTR lpCommandLine = NULL; // 命令行参数为空（仅启动程序）
    STARTUPINFOW si = {0};
    si.cb = sizeof(STARTUPINFOW); // 必须初始化，否则 CreateProcess 会失败
    PROCESS_INFORMATION pi = {0};

    BOOL success = CreateProcessW(
        lpApplicationName,  // 第一个参数：明确传服务器路径（最可靠）
        lpCommandLine,
        NULL,
        NULL,
        FALSE,
        DETACHED_PROCESS,
        NULL,
        NULL,
        &si,
        &pi
        );

    if (success)
    {
        qDebug() << "服务器启动成功，PID:" << pi.dwProcessId;
        serverPid = pi.dwProcessId;
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        startMonitoring(serverPid);

        LogMessage msg;
        msg.content="服务器启动";
        msg.level=LogMessage::Debug;
        msg.timestamp= QDateTime::currentDateTime();

        this->logwriter->writeQueue(msg);
    }
    else
    {
        DWORD err = GetLastError();
        // 输出详细信息，便于排查
        QString errMsg = QString("服务器启动失败\n错误码: %1\n路径: %2\n是否存在该文件？").arg(err).arg(serverPath);
        qDebug() << errMsg;
        QMessageBox::warning(this, "错误", errMsg);


        LogMessage msg;
        msg.content="服务器启动失败";
        msg.level=LogMessage::Debug;
        msg.timestamp= QDateTime::currentDateTime();
        this->logwriter->writeQueue(msg);
    }

#elif defined(Q_OS_LINUX)
    QProcess *process = new QProcess(this);
    process->setProgram(serverPath);
    process->setArguments(QStringList());

    qint64 pid;
    if (QProcess::startDetached(serverPath, QStringList(), QString(), &pid)) {
        serverPid = static_cast<DWORD>(pid);
        qDebug() << "服务器启动成功，PID:" << serverPid;
        startMonitoring(serverPid);

        LogMessage msg;
        msg.content = "服务器启动";
        msg.level = LogMessage::Debug;
        msg.timestamp = QDateTime::currentDateTime();
        this->logwriter->writeQueue(msg);
    } else {
        QString errMsg = QString("服务器启动失败\n路径: %1\n是否存在该文件？").arg(serverPath);
        qDebug() << errMsg;
        QMessageBox::warning(this, "错误", errMsg);

        LogMessage msg;
        msg.content = "服务器启动失败";
        msg.level = LogMessage::Debug;
        msg.timestamp = QDateTime::currentDateTime();
        this->logwriter->writeQueue(msg);
    }
#endif
}




QList<DWORD> Widget::findPidByProcessName(const QString& processName)
{
    QList<DWORD> pids;

#ifdef Q_OS_WIN
    HANDLE hSnapshot =CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//快照所有进程
    if(hSnapshot==INVALID_HANDLE_VALUE)
    {
        qDebug() << "创建进程快照失败，错误码:" << GetLastError();
        return pids;
    }


    PROCESSENTRY32W pe = {0};
    pe.dwSize = sizeof(PROCESSENTRY32W); // 必须初始化大小

    // 遍历第一个进程
    if (Process32FirstW(hSnapshot, &pe)) {
        do {

            QString currentProcessName = QString::fromWCharArray(pe.szExeFile).toLower();
            if (currentProcessName == processName.toLower()) {
                pids.append(pe.th32ProcessID);
                qDebug() << "找到进程:" << pe.szExeFile << "，PID:" << pe.th32ProcessID;
            }
        } while (Process32NextW(hSnapshot, &pe));
    }

    CloseHandle(hSnapshot);
#elif defined(Q_OS_LINUX)
    DIR* dir = opendir("/proc");
    if (!dir) {
        qDebug() << "无法打开/proc目录";
        return pids;
    }

    struct dirent* entry;
    while ((entry = readdir(dir)) != nullptr) {
        if (entry->d_type == DT_DIR) {
            QString dirName = QString(entry->d_name);
            bool ok;
            int pid = dirName.toInt(&ok);
            if (ok) {
                QString exePath = QString("/proc/%1/exe").arg(pid);
                char buf[PATH_MAX];
                ssize_t len = readlink(exePath.toUtf8().constData(), buf, sizeof(buf)-1);
                if (len != -1) {
                    buf[len] = '\0';
                    QString fullPath = QString::fromUtf8(buf);
                    QFileInfo fi(fullPath);
                    if (fi.fileName().compare(processName, Qt::CaseInsensitive) == 0) {
                        pids.append(pid);
                    }
                }
            }
        }
    }
    closedir(dir);
#endif
    return pids;
}








bool Widget::isPidUsingTargetPort(DWORD pid, const DWORD targetPort)
{
#ifdef Q_OS_WIN
    DWORD bufferSize = 0;
    DWORD err = GetExtendedTcpTable(nullptr, &bufferSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
    if (err != ERROR_INSUFFICIENT_BUFFER) {
        qDebug() << "获取TCP表大小失败，错误码:" << err;
        return false;
    }

    PMIB_TCPTABLE_OWNER_PID tcpTable = (PMIB_TCPTABLE_OWNER_PID)new BYTE[bufferSize];
    if (GetExtendedTcpTable(tcpTable, &bufferSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) != NO_ERROR) {
        delete[] tcpTable;
        qDebug() << "获取TCP连接失败，错误码:" << GetLastError();
        return false;
    }

    bool isUsing = false;
    for (DWORD i = 0; i < tcpTable->dwNumEntries; i++) {
        if (tcpTable->table[i].dwOwningPid != pid) {
            continue;
        }

        WORD localPort = ntohs(tcpTable->table[i].dwLocalPort);
        if (localPort == targetPort) {
            if (tcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN ||
                tcpTable->table[i].dwState == MIB_TCP_STATE_ESTAB) {
                isUsing = true;
                break;
            }
        }
    }

    delete[] tcpTable;
    return isUsing;
#elif defined(Q_OS_LINUX)
    // 在Linux上使用lsof命令检查端口占用
    QString command = QString("lsof -i :%1 -t 2>/dev/null").arg(targetPort);
    FILE* pipe = popen(command.toUtf8().constData(), "r");
    if (!pipe) {
        qDebug() << "无法执行lsof命令";
        return false;
    }

    char buffer[128];
    bool found = false;
    while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
        int foundPid = atoi(buffer);
        if (foundPid == pid) {
            found = true;
            break;
        }
    }
    pclose(pipe);
    return found;
#endif
}





void Widget::updateTableRow(int row)
{
    ui->processTable->setItem(row, 0, new QTableWidgetItem(monitoredProcess.name));
    ui->processTable->setItem(row, 1, new QTableWidgetItem(QString::number(monitoredProcess.pid)));
    ui->processTable->setItem(row, 2, new QTableWidgetItem(monitoredProcess.netState));
    ui->processTable->setItem(row, 3, new QTableWidgetItem(monitoredProcess.localIpPort));
    ui->processTable->setItem(row, 4, new QTableWidgetItem(monitoredProcess.cpuUsage));
    ui->processTable->setItem(row, 5, new QTableWidgetItem(monitoredProcess.memoryUsage));
}


void Widget::startMonitoring(DWORD pid)
{
    QString serverName =
#ifdef Q_OS_WIN
        "Server.exe";
#elif defined(Q_OS_LINUX)
        "server";
#endif

    qDebug() << "开始监测进程: PID=" << pid << "，进程名=" << serverName;
    networkProblemDetected = false;
    lastNetworkState = "未知";
    monitoredProcess = {0};
    monitoredProcess.pid = pid;
    monitoredProcess.name = serverName;
    monitoredProcess.cpuUsage = "0.0%";
    monitoredProcess.memoryUsage = "0.0 MB";
    monitoredProcess.netState = "初始化中";
    monitoredProcess.localIpPort = "未知";

#ifdef Q_OS_WIN
    monitoredProcess.lastKernelTime = {0, 0};
    monitoredProcess.lastUserTime = {0, 0};
#elif defined(Q_OS_LINUX)
    monitoredProcess.lastUserTime = 0;
    monitoredProcess.lastKernelTime = 0;
    monitoredProcess.lastTotalJiffies = 0;
#endif

#ifdef Q_OS_WIN
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (hProcess) {
        FILETIME dummy1, dummy2;
        if (!GetProcessTimes(hProcess, &dummy1, &dummy2,
                             &monitoredProcess.lastKernelTime,
                             &monitoredProcess.lastUserTime)) {
            qDebug() << "GetProcessTimes 初始化失败，错误码:" << GetLastError();
            GetSystemTimeAsFileTime(&monitoredProcess.lastKernelTime);
            GetSystemTimeAsFileTime(&monitoredProcess.lastUserTime);
        }

        WCHAR processNameBuf[MAX_PATH] = {0};
        DWORD nameLen = GetModuleBaseNameW(
            hProcess,
            nullptr,
            processNameBuf,
            MAX_PATH
            );
        if (nameLen > 0) {
            monitoredProcess.name = QString::fromWCharArray(processNameBuf, nameLen);
        }
        CloseHandle(hProcess);
    } else {
        qDebug() << "打开进程句柄失败，错误码:" << GetLastError();
    }
#elif defined(Q_OS_LINUX)
    // 在Linux上，我们可以通过读取/proc/[pid]/comm获取进程名
    QString commPath = QString("/proc/%1/comm").arg(pid);
    QFile commFile(commPath);
    if (commFile.open(QIODevice::ReadOnly)) {
        QString name = QString::fromUtf8(commFile.readAll()).trimmed();
        if (!name.isEmpty()) {
            monitoredProcess.name = name;
        }
    }
    commFile.close();

    // 初始化CPU时间
    QString statPath = QString("/proc/%1/stat").arg(pid);
    QFile statFile(statPath);
    if (statFile.open(QIODevice::ReadOnly)) {
        QString statContent = QString::fromUtf8(statFile.readAll());
        statFile.close();

        QStringList statFields = statContent.split(' ');
        if (statFields.size() >= 17) {
            monitoredProcess.lastUserTime = statFields[13].toLong();
            monitoredProcess.lastKernelTime = statFields[14].toLong();
        }
    }

    // 初始化系统总时间
    QFile procStatFile("/proc/stat");
    if (procStatFile.open(QIODevice::ReadOnly)) {
        QString procStatContent = QString::fromUtf8(procStatFile.readLine());
        procStatFile.close();

        QStringList cpuFields = procStatContent.split(' ', Qt::SkipEmptyParts);
        if (cpuFields.size() >= 8) {
            for (int i = 1; i < 8; i++) {
                monitoredProcess.lastTotalJiffies += cpuFields[i].toLong();
            }
        }
    }
#endif

    ui->processTable->setRowCount(1);
    updateTableRow(0);

    isMonitoring = true;
    updateTimer->start(1000);
    qDebug() << "监测启动成功，定时器已开启";
}





void Widget::on_startButton_clicked()
{
    qDebug()<<"点击启动";
    loadProcesses();
}


void Widget::on_processErrorOccurred()
{
    if (isNetworkDisconnected) {
        qDebug() << "网络已断开，跳过进程重启逻辑";
        return;
    }

    if (isRestarting) {
        return; // 正在重启，跳过检查
    }

#ifdef Q_OS_WIN
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, serverPid);
    if (hProcess) {
        DWORD exitCode;
        GetExitCodeProcess(hProcess, &exitCode);
        CloseHandle(hProcess);

        if (exitCode != STILL_ACTIVE) {
            qDebug() << "服务器进程已退出，尝试重启（PID=" << serverPid << "）";
            restartServer();

            LogMessage msg;
            msg.content = "服务器进程已退出，尝试重启";
            msg.level = LogMessage::Debug;
            msg.timestamp = QDateTime::currentDateTime();
            this->logwriter->writeQueue(msg);
        }
    } else {
        DWORD err = GetLastError();
        qDebug() << "打开进程失败，PID=" << serverPid << "，错误码:" << err;
        LogMessage msg;
        msg.content = QString("打开进程失败，PID=%1，错误码=%2").arg(serverPid).arg(err);
        msg.level = LogMessage::Error;
        logwriter->writeQueue(msg);
        restartServer();
    }
#elif defined(Q_OS_LINUX)
    // 在Linux上，检查进程是否存在
    QString procPath = QString("/proc/%1").arg(serverPid);
    QDir procDir(procPath);

    if (!procDir.exists()) {
        qDebug() << "服务器进程已退出，尝试重启（PID=" << serverPid << "）";
        restartServer();

        LogMessage msg;
        msg.content = "服务器进程已退出，尝试重启";
        msg.level = LogMessage::Debug;
        msg.timestamp = QDateTime::currentDateTime();
        this->logwriter->writeQueue(msg);
    }
#endif
}


void Widget::restartServer()
{
    if (isRestarting) {
        qDebug() << "已在重启过程中，跳过重复重启";
        return;
    }

    if (serverPath.isEmpty()) {
        qDebug() << "重启失败：服务器路径未设置";
        QMessageBox::warning(this, "错误", "重启失败：服务器路径未设置");
        return;
    }

    isRestarting = true; // 设置重启标志

    stopMonitoring();

#ifdef Q_OS_WIN
    std::wstring widePath = serverPath.toStdWString();
    LPCWSTR lpApplicationName = widePath.c_str();
    LPWSTR lpCommandLine = NULL;

    STARTUPINFOW si = {0};
    si.cb = sizeof(STARTUPINFOW);
    PROCESS_INFORMATION pi = {0};

    BOOL success = CreateProcessW(
        lpApplicationName,
        lpCommandLine,
        NULL,
        NULL,
        FALSE,
        DETACHED_PROCESS,
        NULL,
        NULL,
        &si,
        &pi
        );

    if (success) {
        qDebug() << "服务器重启成功，新 PID:" << pi.dwProcessId;
        serverPid = pi.dwProcessId;
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        // 延迟一段时间再开始监控，给服务器启动时间
        QTimer::singleShot(3000, this, [this]() {
            startMonitoring(serverPid);
            isRestarting = false; // 重置重启标志
        });
        ui->processTable->setItem(0, 2, new QTableWidgetItem("已重启"));

        LogMessage msg;
        msg.content = "服务器进程重启成功";
        msg.level = LogMessage::Debug;
        msg.timestamp = QDateTime::currentDateTime();
        this->logwriter->writeQueue(msg);
    } else {
        DWORD err = GetLastError();
        QString errMsg = QString("服务器重启失败\n错误码: %1\n路径: %2").arg(err).arg(serverPath);
        qDebug() << errMsg;
        QMessageBox::warning(this, "错误", errMsg);
        isRestarting = false; // 重置重启标志
    }
#elif defined(Q_OS_LINUX)
    QProcess *process = new QProcess(this);
    process->setProgram(serverPath);
    process->setArguments(QStringList());

    qint64 pid;
    if (QProcess::startDetached(serverPath, QStringList(), QString(), &pid)) {
        serverPid = static_cast<DWORD>(pid);
        qDebug() << "服务器启动成功，PID:" << serverPid;
        startMonitoring(serverPid);

        LogMessage msg;
        msg.content = "服务器启动";
        msg.level = LogMessage::Debug;
        msg.timestamp = QDateTime::currentDateTime();
        this->logwriter->writeQueue(msg);
    } else {
        QString errMsg = QString("服务器重启失败\n路径: %1").arg(serverPath);
        qDebug() << errMsg;
        QMessageBox::warning(this, "错误", errMsg);
        isRestarting = false; // 重置重启标志
    }
#endif
}



void Widget::updateProcessInfo()
{
    if(!isMonitoring||monitoredProcess.pid==0) return;
    //更新内存
    monitoredProcess.memoryUsage=getMemoryUsage(monitoredProcess.pid);

    //更新cpu利用率
    float cpuUsage=calculateCPUUsage(monitoredProcess.pid);
    monitoredProcess.cpuUsage=QString::number(cpuUsage,'f',1)+"%";

    //更新网络信息
    updateNetworkInfo();

    //更新网格
    updateTableRow(0);

    //查看是否崩溃
    on_processErrorOccurred();



    //检查网络并且处理
    checkNetworkStatusAndRestart();



}

QString Widget::getMemoryUsage(DWORD pid)
{
#ifdef Q_OS_WIN
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!hProcess) {
        qDebug() << "getMemoryUsage: 打开进程失败，错误码:" << GetLastError();
        return "获取失败（权限）";
    }

    PROCESS_MEMORY_COUNTERS_EX pmc;
    ZeroMemory(&pmc, sizeof(pmc));
    pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);

    if (!GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, pmc.cb)) {
        CloseHandle(hProcess);
        qDebug() << "getMemoryUsage: 获取内存信息失败，错误码:" << GetLastError();
        return "获取失败（函数）";
    }

    CloseHandle(hProcess);

    DWORD64 privateMem = pmc.PrivateUsage;
    double memMB = privateMem / (1024.0 * 1024.0);
    return memMB < 0.1 ? "0.0 MB" : QString("%1 MB").arg(memMB, 0, 'f', 1);
#elif defined(Q_OS_LINUX)
    QString statusPath = QString("/proc/%1/status").arg(pid);
    QFile statusFile(statusPath);
    if (!statusFile.open(QIODevice::ReadOnly)) {
        return "获取失败";
    }

    QString content = QString::fromUtf8(statusFile.readAll());
    statusFile.close();

    QRegularExpression vmRssRegex("VmRSS:\\s*(\\d+)\\s*kB");
    QRegularExpressionMatch match = vmRssRegex.match(content);
    if (match.hasMatch()) {
        qint64 vmRssKb = match.captured(1).toLongLong();
        double memMB = vmRssKb / 1024.0;
        return memMB < 0.1 ? "0.0 MB" : QString("%1 MB").arg(memMB, 0, 'f', 1);
    }
    return "获取失败";
#endif
}


float Widget::calculateCPUUsage(DWORD pid)
{
    if (pid == 0) return 0.0f;

#ifdef Q_OS_WIN
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!hProcess) {
        qDebug() << "calculateCPUUsage: 无法打开进程，错误码:" << GetLastError();
        return 0.0f;
    }

    FILETIME nowKernelTime, nowUserTime;
    FILETIME creationTime, exitTime;
    if (!GetProcessTimes(hProcess, &creationTime, &exitTime, &nowKernelTime, &nowUserTime)) {
        CloseHandle(hProcess);
        qDebug() << "calculateCPUUsage: 获取时间失败，错误码:" << GetLastError();
        return 0.0f;
    }

    auto fileTimeToUInt64 = [](const FILETIME& ft) -> ULONGLONG {
        ULARGE_INTEGER ul;
        ul.LowPart = ft.dwLowDateTime;
        ul.HighPart = ft.dwHighDateTime;
        return ul.QuadPart;
    };

    ULONGLONG lastTotal = fileTimeToUInt64(monitoredProcess.lastKernelTime) +
                          fileTimeToUInt64(monitoredProcess.lastUserTime);
    ULONGLONG nowTotal = fileTimeToUInt64(nowKernelTime) + fileTimeToUInt64(nowUserTime);
    ULONGLONG totalDiff = nowTotal - lastTotal;

    if (lastTotal == 0) {
        monitoredProcess.lastKernelTime = nowKernelTime;
        monitoredProcess.lastUserTime = nowUserTime;
        CloseHandle(hProcess);
        return 0.0f;
    }

    monitoredProcess.lastKernelTime = nowKernelTime;
    monitoredProcess.lastUserTime = nowUserTime;
    CloseHandle(hProcess);

    float cpuUsage = (totalDiff / 10000.0f) / 10.0f;
    return cpuUsage > 100.0f ? 100.0f : cpuUsage;
#elif defined(Q_OS_LINUX)
    QString statPath = QString("/proc/%1/stat").arg(pid);
    QFile statFile(statPath);
    if (!statFile.open(QIODevice::ReadOnly)) {
        return 0.0f;
    }

    QString statContent = QString::fromUtf8(statFile.readAll());
    statFile.close();

    QStringList statFields = statContent.split(' ');
    if (statFields.size() < 17) {
        return 0.0f;
    }

    long utime = statFields[13].toLong();
    long stime = statFields[14].toLong();
    long cutime = statFields[15].toLong();
    long cstime = statFields[16].toLong();
    long total_time = utime + stime + cutime + cstime;

    QFile procStatFile("/proc/stat");
    if (!procStatFile.open(QIODevice::ReadOnly)) {
        return 0.0f;
    }

    QString procStatContent = QString::fromUtf8(procStatFile.readLine());
    procStatFile.close();

    QStringList cpuFields = procStatContent.split(' ', Qt::SkipEmptyParts);
    if (cpuFields.size() < 8) {
        return 0.0f;
    }

    long total_jiffies = 0;
    for (int i = 1; i < 8; i++) {
        total_jiffies += cpuFields[i].toLong();
    }

    if (monitoredProcess.lastTotalJiffies == 0) {
        monitoredProcess.lastUserTime = total_time;
        monitoredProcess.lastTotalJiffies = total_jiffies;
        return 0.0f;
    }

    long delta_time = total_time - monitoredProcess.lastUserTime;
    long delta_jiffies = total_jiffies - monitoredProcess.lastTotalJiffies;

    monitoredProcess.lastUserTime = total_time;
    monitoredProcess.lastTotalJiffies = total_jiffies;

    if (delta_jiffies == 0) {
        return 0.0f;
    }

    float cpuUsage = 100.0f * delta_time / delta_jiffies;
    return cpuUsage > 100.0f ? 100.0f : cpuUsage;
#endif
}


void Widget::updateNetworkInfo()
{
#ifdef Q_OS_WIN
    DWORD bufferSize = 0;
    GetExtendedTcpTable(nullptr, &bufferSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
    if (bufferSize == 0) {
        monitoredProcess.netState = "无连接";
        monitoredProcess.localIpPort = "";
        return;
    }

    PMIB_TCPTABLE_OWNER_PID tcpTable = (PMIB_TCPTABLE_OWNER_PID)new BYTE[bufferSize];
    if (GetExtendedTcpTable(tcpTable, &bufferSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) != NO_ERROR) {
        delete[] tcpTable;
        monitoredProcess.netState = "获取失败";
        return;
    }

    bool hasConnection = false;
    for (DWORD i = 0; i < tcpTable->dwNumEntries; i++) {
        if (tcpTable->table[i].dwOwningPid == monitoredProcess.pid) {
            QString localIp = formatIp(tcpTable->table[i].dwLocalAddr);
            QString localPort = formatPort(tcpTable->table[i].dwLocalPort);

            monitoredProcess.localIpPort = localIp + ":" + localPort;

            switch (tcpTable->table[i].dwState) {
            case MIB_TCP_STATE_ESTAB:
                monitoredProcess.netState = "活跃";
                break;
            case MIB_TCP_STATE_LISTEN:
                monitoredProcess.netState = "监听中";
                break;
            case MIB_TCP_STATE_TIME_WAIT:
            case MIB_TCP_STATE_CLOSE_WAIT:
                monitoredProcess.netState = "闲置";
                break;
            default:
                monitoredProcess.netState = "连接中";
            }

            hasConnection = true;
            break;
        }
    }

    if (!hasConnection) {
        monitoredProcess.netState = "无连接";
        monitoredProcess.localIpPort = "";
    }

    delete[] tcpTable;
#elif defined(Q_OS_LINUX)
    QFile tcpFile("/proc/net/tcp");
    if (!tcpFile.open(QIODevice::ReadOnly)) {
        monitoredProcess.netState = "获取失败";
        monitoredProcess.localIpPort = "";
        return;
    }

    tcpFile.readLine(); // 跳过标题行

    bool hasConnection = false;
    while (!tcpFile.atEnd()) {
        QString line = QString::fromUtf8(tcpFile.readLine());
        QStringList fields = line.split(' ', Qt::SkipEmptyParts);
        if (fields.size() < 10) continue;

        QString inode = fields[9];

        QString fdPath = QString("/proc/%1/fd").arg(monitoredProcess.pid);
        QDir fdDir(fdPath);
        if (!fdDir.exists()) continue;

        QStringList fdEntries = fdDir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
        for (const QString& fd : fdEntries) {
            QString fdLink = fdDir.absoluteFilePath(fd);
            QString linkedTo = QFile::symLinkTarget(fdLink);

            if (linkedTo.contains("socket:[" + inode + "]")) {
                QString localAddress = fields[1];
                QStringList addrPort = localAddress.split(':');
                if (addrPort.size() != 2) continue;

                QString ip = formatLinuxIp(addrPort[0]);
                QString port = formatLinuxPort(addrPort[1]);

                monitoredProcess.localIpPort = ip + ":" + port;

                QString stateHex = fields[3];
                bool ok;
                int state = stateHex.toInt(&ok, 16);
                if (!ok) continue;

                switch (state) {
                case 1: // TCP_ESTABLISHED
                    monitoredProcess.netState = "活跃";
                    break;
                case 10: // TCP_LISTEN
                    monitoredProcess.netState = "监听中";
                    break;
                case 6: // TCP_TIME_WAIT
                case 8: // TCP_CLOSE_WAIT
                    monitoredProcess.netState = "闲置";
                    break;
                default:
                    monitoredProcess.netState = "连接中";
                }

                hasConnection = true;
                break;
            }
        }

        if (hasConnection) break;
    }

    tcpFile.close();

    if (!hasConnection) {
        monitoredProcess.netState = "无连接";
        monitoredProcess.localIpPort = "";
    }
#endif
}


void Widget::checkNetworkStatusAndRestart()
{


    bool currentPhysicalNetState =isPhysicalNetworkConnected();


    QString currentState = monitoredProcess.netState;



    if(!lastPhysicalNetworkState&&currentPhysicalNetState)
    {
        qDebug() << "物理网络已恢复，触发服务器重启";
        ui->processTable->setItem(0, 2, new QTableWidgetItem("物理网络恢复，重启中"));

        isNetworkDisconnected = false;
        lastPhysicalNetworkState = currentPhysicalNetState;



        // 2. 先杀死残留的旧服务（防止端口占用）
        if (serverPid != 0) {
            killAllOldProcesses(serverPid);
            serverPid = 0; // 重置PID，避免后续误判
        }



        //记录日志重启
        LogMessage msg;

        msg.content="物理网络从断开状态恢复，重启服务器";
        msg.level=LogMessage::Debug;
        msg.timestamp=QDateTime::currentDateTime();
        this->logwriter->writeQueue(msg);


        restartServer();//重启

        networkProblemDetected=false;
        lastPhysicalNetworkState = currentPhysicalNetState;  // 更新物理网络状态
        lastNetworkState = currentState;  // 更新进程网络状态
        return;
    }

    if (currentPhysicalNetState == false) {
        if (lastPhysicalNetworkState != currentPhysicalNetState) {
            qDebug() << "物理网络已断开，标记网络异常";
            ui->processTable->setItem(0, 2, new QTableWidgetItem("物理网络断开"));

            // 1. 标记网络已断开（禁止重启）
            isNetworkDisconnected = true;

            // 2. 杀死当前服务
            if (serverPid != 0) {
                killAllOldProcesses(serverPid);
                serverPid = 0; // 重置PID，避免后续误判
            }
            LogMessage msg;
            msg.content = "检测到物理网络断开";
            msg.level = LogMessage::Warning;
            msg.timestamp = QDateTime::currentDateTime();
            this->logwriter->writeQueue(msg);


        }
        networkProblemDetected = true;  // 标记网络异常
        lastPhysicalNetworkState = currentPhysicalNetState;  // 更新物理网络状态
        lastNetworkState = currentState;  // 更新进程网络状态
        return;
    }



    if ((lastNetworkState == "无连接" || lastNetworkState == "获取失败")
        && (currentState == "活跃" || currentState == "监听中"))
    {
        if (networkProblemDetected)
        {
            qDebug() << "网络从" << lastNetworkState << "恢复到" << currentState << "，重启进程...";
            // 修复表格越界：更新“网络状态”列（索引 2），而非不存在的索引 6
            ui->processTable->setItem(0, 2, new QTableWidgetItem("网络恢复，重启中"));

            restartServer();
            networkProblemDetected = false;
        }
    }
    lastNetworkState = currentState;
}


void Widget::stopMonitoring()
{
    if(!isMonitoring) return;
    updateTimer->stop();
    // // 终止服务器进程
    // if (serverProcess && serverProcess->state() == QProcess::Running) {
    //     serverProcess->terminate();
    //     if (!serverProcess->waitForFinished(3000)) {
    //         serverProcess->kill();
    //     }
    //     delete serverProcess;
    //     serverProcess = nullptr;
    // }

    isMonitoring = false;
    // ui->processTable->setItem(0, 6, new QTableWidgetItem("已停止"));
    qDebug() << "监测已停止";
}



#ifdef Q_OS_WIN
QString Widget::formatIp(DWORD ip)
{
    BYTE *ipBytes = (BYTE*)&ip;
    return QString("%1.%2.%3.%4")
        .arg((int)ipBytes[0])
        .arg((int)ipBytes[1])
        .arg((int)ipBytes[2])
        .arg((int)ipBytes[3]);
}

QString Widget::formatPort(WORD port)
{
    return QString::number(ntohs(port));
}
#elif defined(Q_OS_LINUX)
QString Widget::formatLinuxIp(const QString &ipHex)
{
    bool ok;
    quint32 ipNum = ipHex.toUInt(&ok, 16);
    if (!ok) return "0.0.0.0";

    // 转换字节序
    ipNum = (ipNum >> 24) | ((ipNum >> 8) & 0xFF00) |
            ((ipNum << 8) & 0xFF0000) | (ipNum << 24);

    return QString("%1.%2.%3.%4")
        .arg((ipNum >> 24) & 0xFF)
        .arg((ipNum >> 16) & 0xFF)
        .arg((ipNum >> 8) & 0xFF)
        .arg(ipNum & 0xFF);
}

QString Widget::formatLinuxPort(const QString &portHex)
{
    bool ok;
    quint16 port = portHex.toUShort(&ok, 16);
    if (!ok) return "0";
    return QString::number(port);
}
#endif



void Widget::on_selectButton_clicked()
{
#ifdef Q_OS_WIN
    QString filter = tr("可执行程序(*.exe)");
#elif defined(Q_OS_LINUX)
    QString filter = tr("可执行程序(*)");
#endif

    QString selectedPath = QFileDialog::getOpenFileName(this, tr("选择服务器可执行程序"),
                                                        QCoreApplication::applicationDirPath(), filter);

    if (selectedPath.isEmpty()) {
        isSelect = false;
        QMessageBox::information(this, "提示", "没有对应的可执行程序");
    } else {
        QFile file(selectedPath);
        if (!file.exists()) {
            isSelect = false;
            QMessageBox::warning(this, "提示", "没有对应的文件");
            return;
        }

        serverPath = selectedPath;
        isSelect = true;
        QString tips = QString("已选择程序：\n%1").arg(serverPath);
        QMessageBox::information(this, "选择成功", tips);
        ui->startButton->setEnabled(true);
    }
}


bool Widget::isPhysicalNetworkConnected()
{
#ifdef Q_OS_WIN
    DWORD dwError = 0;
    HANDLE hClient = NULL;
    PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
    bool isConnected = false;

    dwError = WlanOpenHandle(2, NULL, &dwError, &hClient);

    if (dwError != ERROR_SUCCESS || hClient == NULL) {
        qDebug() << "WlanOpenHandle 失败，错误码:" << dwError;
        goto Cleanup;
    }

    //获取所有网络接口
    dwError = WlanEnumInterfaces(hClient, NULL, &pIfList);
    if (dwError != ERROR_SUCCESS || pIfList == NULL) {
        qDebug() << "WlanEnumInterfaces 失败，错误码:" << dwError;
        goto Cleanup;
    }

    //遍历
    for (DWORD i = 0; i < pIfList->dwNumberOfItems; i++) {
        PWLAN_INTERFACE_INFO pIfInfo = &pIfList->InterfaceInfo[i];
        QString ifDesc = QString::fromWCharArray(pIfInfo->strInterfaceDescription);

        if (ifDesc.contains("Virtual", Qt::CaseInsensitive) ||  // 排除虚拟网卡
            ifDesc.contains("VMware", Qt::CaseInsensitive) ||  // 排除 VMware 虚拟网卡
            ifDesc.contains("Hyper-V", Qt::CaseInsensitive)) { // 排除 Hyper-V 虚拟网卡
            continue;
        }

        if (pIfInfo->isState == wlan_interface_state_connected) {
            isConnected = true;
            qDebug() << "物理网卡已连接：" << ifDesc;
            break;  //有一个网卡就是网络正常
        }
    }

Cleanup:
    // 4. 释放资源（避免内存泄漏）
    if (pIfList != NULL) {
        WlanFreeMemory(pIfList);
    }
    if (hClient != NULL) {
        WlanCloseHandle(hClient, NULL);
    }

    return isConnected;
#elif defined(Q_OS_LINUX)
    // Linux实现：检查网络接口状态
    QProcess process;
    process.start("nmcli", QStringList() << "-t" << "device" << "status");
    process.waitForFinished();

    QString output = process.readAllStandardOutput();
    QStringList lines = output.split('\n', Qt::SkipEmptyParts);

    for (const QString &line : lines) {
        QStringList parts = line.split(':');
        if (parts.size() >= 4) {
            QString device = parts[0];
            QString state = parts[3];

            // 排除虚拟设备
            if (device.startsWith("virbr") || device.startsWith("veth") ||
                device.startsWith("docker") || device.startsWith("br-")) {
                continue;
            }

            if (state == "connected") {
                qDebug() << "物理网卡已连接：" << device;
                return true;
            }
        }
    }

    return false;
#endif
}


bool Widget::killAllOldProcesses(DWORD pid)
{
    // 跳过无效PID
    if (pid == 0) {
        qDebug() << "无效PID，不执行终止操作";
        return false;
    }

#ifdef Q_OS_WIN
    // 打开进程并获取终止权限
    HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
    if (!hProcess) {
        DWORD err = GetLastError();
        qDebug() << "无法打开进程（PID=" << pid << "），错误码:" << err;
        return false;
    }

    // 强制终止进程
    bool success = TerminateProcess(hProcess, 0) != 0;
    if (success) {
        qDebug() << "已成功终止进程，PID=" << pid;
        // 等待进程退出（最多2秒）
        WaitForSingleObject(hProcess, 2000);

        LogMessage msg;
        msg.content = QString("进程已终止（PID=%1）").arg(pid);
        msg.level = LogMessage::Info;
        logwriter->writeQueue(msg);
    } else {
        DWORD err = GetLastError();
        qDebug() << "终止进程失败（PID=" << pid << "），错误码:" << err;
    }

    // 释放句柄
    CloseHandle(hProcess);
    return success;
#elif defined(Q_OS_LINUX)
    // Linux实现：使用kill命令终止进程
    int result = kill(pid, SIGTERM);
    if (result == 0) {
        qDebug() << "已发送终止信号给进程，PID=" << pid;

        // 等待进程退出
        QProcess process;
        process.start("kill", QStringList() << "-0" << QString::number(pid));
        process.waitForFinished(2000);

        if (process.exitCode() == 0) {
            // 进程仍然存在，强制终止
            kill(pid, SIGKILL);
            qDebug() << "强制终止进程，PID=" << pid;
        }

        LogMessage msg;
        msg.content = QString("进程已终止（PID=%1）").arg(pid);
        msg.level = LogMessage::Info;
        logwriter->writeQueue(msg);

        return true;
    } else {
        qDebug() << "终止进程失败（PID=" << pid << "），错误码:" << errno;
        return false;
    }
#endif
}




